home *** CD-ROM | disk | FTP | other *** search
/ Wayzata's Best of Shareware PC/Windows 1 / Wayzata's Best of Shareware for PC-Windows - Release 1 - Wayzata Technology (1993).iso / mac / DOS / GRAPHICS / LISS151 / LISSAJOU.C < prev    next >
C/C++ Source or Header  |  1992-04-20  |  29KB  |  813 lines

  1. /**************************
  2.   LISSAJOU.C
  3.       This program displays spherical Lissajous figures
  4.       and writes a data file in either Vivid, Persistence of Vision
  5.       (PoV), or Connect the Dots Smoother (CTDS) format.
  6.  
  7.       Program originally written by Dan Farmer using algorithms from
  8.       Clifford Pickover.  Converted from QuickBasic to C by Aaron C. Caba.
  9.       See Scientific American January 1991 and Omni February 1990 for
  10.       excellent examples by Pickover.
  11.  
  12.       Compiled with Turbo C++ 1.0 under the LARGE memmory model
  13.  
  14. History:
  15.  
  16.  Version 1.51:
  17.     Stuff left to do:
  18.         ESC problems in rotate routine.
  19.         guibolt has never quite worked right.
  20.  
  21.   04/14/92 ACC fix rotate_fig/disp_spheres/quiksort so they all can rotate
  22.                and display around any axis
  23.                Add axis display on viewing screen
  24.  
  25.  Version 1.5:
  26.  
  27.   03/10/92 ACC I decided to change to version number to differentiate
  28.                this from some V. 1.4 betas running around.
  29.                Add the equation display on the main screen
  30.  
  31.   03/09/92 ACC Finally was able to change to the Large memmory model --
  32.                I found that I was running out of stack space.
  33.  
  34.  Version 1.4:
  35.   02/11/92 ACC Major rearangement of all code:
  36.                move all field manipulation functions to FIELD.C
  37.                clean up header files so only necessary stuff is in each
  38.  
  39.    1/07/92 ACC Change all scatered calls to 'exit()' to error_fn.
  40.   12/04/91 ACC Begin converting Dan's original Basic code to C.
  41.                Add Vivid output, CTDS output, change DKB to PoV output.
  42.                Write up some kind of documentation.
  43.  
  44.  Version 1.3:
  45.   03/08/91 DMF Drop FRACTINT color map option.  Doubt if anyone uses it.
  46.                Make colors all color declarations and use the names in
  47.                the objects, rather than the values.  Easier to edit when
  48.                you have 100s of objects and several colors to change.
  49.  
  50.   01/16/90 DMF Change most GOSUBS to SUBPROGRAMS and FUNCTIONS
  51.                Specify type of most integers. (Default is single precision)
  52.                Replace Shellsort with Quicksort
  53.                Allow pausing of display, with option to write only the
  54.                spheres displayed.
  55.                Use Fractint color map or specified color(s) for DKB script.
  56.  
  57.  Revision: DMF Add EXPONENT variable
  58.                Bug Fix: CLOSE #1 when finished with it.
  59.                In WRITE.HEADER, use correct variable for R1 reference.
  60.  *************************/
  61.  
  62. #include "lissajou.h"
  63.  
  64. /* ****************************** functions ****************************** */
  65.  
  66. /* Initalize the 'field' variable with:
  67.                 field label
  68.                       length
  69.                       screen (x,y) position
  70.                       type
  71. */
  72. void initfield(char *data[])
  73. {
  74.     int i,
  75.         rotate_dy=0;
  76.  
  77.     if(getgraphmode() == VGAHI) rotate_dy=13;
  78.  
  79.  
  80.     /* the labels and default data for the data fields */
  81.     for(i=0; i<MAXFIELDS; i++) {
  82.         strcpy(field[i].label,label[i]);
  83.         strcpy(data[i],field_default[i]);
  84.     }
  85.     /* length of each field */
  86.     field[MAIN_RADIUS].len=3;   field[A].len=4;
  87.     field[B].len=4;             field[EXPONENT_X].len=1;
  88.     field[EXPONENT_Y].len=1;    field[EXPONENT_Z].len=1;
  89.     field[SPH_RADIUS].len=2;    field[SPHERES].len=4;
  90.     field[AXIS].len=1;          field[ALGO].len=1;
  91.     field[ROTATE].len=4;        field[FILE_NAME].len=8;
  92.     field[NUMCOLORS].len=2;     field[COLOR_NAME].len=45;
  93.     field[ALGO_EQN].len=1;
  94.  
  95.     /* set text (x,y) coord's of each field */
  96.     for(i=0; i< PARMFIELDS; i++) {  
  97.         field[i].x=2;
  98.         field[i].y=(i+3);
  99.     }
  100.     field[ROTATE].x=48;     field[ROTATE].y=MESSAGE_Y_POS+rotate_dy;
  101.     field[FILE_NAME].x=37;  field[FILE_NAME].y=2;
  102.     field[NUMCOLORS].x=55;  field[NUMCOLORS].y=2;
  103.     field[COLOR_NAME].x=33; field[COLOR_NAME].y=4;
  104.     field[ALGO_EQN].x=2;    field[ALGO_EQN].y=14;
  105.  
  106.     /* set what 'type' each field contains */
  107.     for(i=0; i < PARMFIELDS; i++) field[i].type=INTEGER;
  108.     field[A].type=field[B].type=DECIMAL;
  109.     field[AXIS].type=XYZ;
  110.     field[ROTATE].type=SIGNED_INTEGER;
  111.     field[FILE_NAME].type=ALPHA;
  112.     field[NUMCOLORS].type=INTEGER;
  113.     field[COLOR_NAME].type=ALPHA;
  114. } /* end initfield */
  115.  
  116. extern unsigned _stklen=64000U;     /* This value works, but a smaller 
  117.                                        one might work also -- ACC      */
  118.  
  119.  
  120. /* ============================= main() =================================== */
  121. int main(void) {
  122.     int
  123. /*        gdriver=DETECT, gmode, */
  124. /*        gdriver=VGA, gmode=VGAHI, */
  125.         gdriver=EGA, gmode=EGAHI,
  126.         errorcode,
  127.         main_radius,                    /* over-all radius of figure        */
  128.         exponent_x, exponent_y,         /* exponenets for figure generation */
  129.         exponent_z,
  130.         spheres,                        /* number of spheres in figure      */
  131.         algo,                           /* which algorithm to use           */
  132.         t,                              /* loop "time" variable             */
  133.         i,                              /* scratch counter variable         */
  134.         exitflag,                       /* if TRUE, then exit               */
  135.         index[MAXSPHERES],              /* array used to order spheres      */
  136.         done;                           /* flag if function is done         */
  137.     float x,y,z,                        /* coords of current point          */
  138.           a,b;                          /* parameters for figure generation */
  139.     char *data[MAXFIELDS],              /* holds user inputed parameters    */
  140.          ch;                            /* input to choose Output/Rotate/ect. */
  141.  
  142.     /* queue holds (x,y,z) and scaled radius    */
  143.     struct queue_type queue[MAXSPHERES];
  144.  
  145. #ifdef DEBUG
  146.     char msg[40];   /* debug var */
  147.     unsigned long debug; /* a debugging variable */
  148.  
  149.     printf("The stack length is: %u\n",_stklen);
  150.     getch();
  151. #endif
  152.  
  153.     /* init 'data' strings */
  154.     for(i=0; i<MAXFIELDS; i++) {
  155.         if ((data[i]=malloc((MAX_FIELD_LEN+1)*sizeof(char))) == NULL)
  156.             error_fn(EMEM,"data[] init");
  157.         strcpy(data[i],"");
  158.     }
  159.  
  160.     /* initalize the graphics system */
  161.     registerbgidriver(EGAVGA_driver);
  162.     initgraph(&gdriver, &gmode, "");    /* initalize EGA graphics           */
  163.     errorcode = graphresult();          /* read result of initgraph call    */
  164.     if (errorcode != grOk)              /* an error occurred                */
  165.         error_fn(EGRAPH,grapherrormsg(errorcode));
  166.  
  167.     setvisualpage(0);   /* choose graphics page #0 for output */
  168.     setactivepage(0);
  169.  
  170.     /* initalize the screen coordinates */
  171.     cols=getmaxx(); rows=getmaxy();
  172.     xcenter=cols/2; ycenter=rows/2;
  173.     wintop=16; winbottom=rows-50;
  174.     winleft=xcenter/2+28; winright=cols-10;
  175.     winxcenter=(winright+winleft)/2-winleft;  /* circles drawn relative to (0,0) */
  176.     winycenter=(winbottom+wintop)/2-wintop;   /* of window, not screen */
  177.  
  178.     /* initalize fields with labels, (x,y) pos, length and type         */
  179.     initfield(data);
  180.     assign_default(data);               /* defaults data for each field */
  181.  
  182. #ifdef DEBUG
  183.     debug=farcoreleft();
  184.     sprintf(msg,"free far core:  %lu",debug);
  185.     disp_message(msg);
  186.     getch();
  187.     debug=coreleft();
  188.     sprintf(msg,"free core:  %lu",debug);
  189.     disp_message(msg);
  190.     getch();
  191. #endif
  192.  
  193.     setbkcolor(EGA_LIGHTGRAY);
  194.     disp_bkground();                    /* draw windows, field labels       */
  195.     disp_data(data);                    /* display current data (defaults)  */
  196.  
  197.     exitflag=edit_parms(data);          /* edit the parameters              */
  198.     while (!exitflag) {
  199.         disp_message("Generating...");
  200.         main_radius=atoi(data[MAIN_RADIUS]);    /* convert data to numbers  */
  201.         a=atof(data[A]);
  202.         b=atof(data[B]);
  203.         exponent_x=atoi(data[EXPONENT_X]);
  204.         exponent_y=atoi(data[EXPONENT_Y]);
  205.         exponent_z=atoi(data[EXPONENT_Z]);
  206.         spheres=atoi(data[SPHERES]);
  207.         algo=atoi(data[ALGO]);
  208.  
  209.         /* now for the calculations */
  210.         for(t=0; t<spheres; t++) {
  211.             switch(algo) {
  212.                 case 1: algo1(t,main_radius,a,b,
  213.                               exponent_x,exponent_y,exponent_z,
  214.                               &x,&y,&z);
  215.                         break;
  216.                 case 2: algo2(t,main_radius,a,b,
  217.                               exponent_x,exponent_y,exponent_z,
  218.                               &x,&y,&z);
  219.                         break;
  220.                 case 3: algo3(t,main_radius,a,b,
  221.                               exponent_x,exponent_y,exponent_z,
  222.                               &x,&y,&z);
  223.                         break;
  224.                 case 4: algo4(t,main_radius,a,b,
  225.                               exponent_x,exponent_y,exponent_z,
  226.                               &x,&y,&z);
  227.                         break;
  228.                 case 5: algo5(t,main_radius,a,b,
  229.                               exponent_x,exponent_y,exponent_z,
  230.                               &x,&y,&z);
  231.                         break;
  232.             }
  233.             index[t]=t;
  234.             queue[t].x=x; queue[t].y=y; queue[t].z=z;
  235.         }
  236.  
  237.         disp_message("Sorting...");
  238.         quicksort(queue, index, 0, spheres-1, data[AXIS]);
  239.         disp_spheres(queue, index, spheres, data);
  240.  
  241.         /* Allow user to choose what to do next:
  242.                 Output a script file
  243.                 Rotate the on-screen image
  244.                 Change generator variables
  245.                 Quit */
  246.         done=FALSE;
  247.         while (!done && !exitflag) {
  248.             disp_message("Finished:  [O]=Output script  [R]=Rotate  [CR]=More  [ESC]=Quit");
  249.             ch=getch();
  250.             switch(ch) {
  251.                 case RETURN: done=TRUE; break;
  252.                 case 'O':
  253.                 case 'o': output(queue,index,spheres,data); break;
  254.                 case 'R':
  255.                 case 'r':
  256.                     rotate_fig(queue, spheres, data[ROTATE], data[AXIS]);
  257.                     disp_message("Sorting...");
  258.                     quicksort(queue, index, 0, spheres-1, data[AXIS]);
  259.                     disp_spheres(queue, index, spheres, data);
  260.                     break;
  261.                 default: if (iscntrl(ch)) {
  262.                              if (ch==ESC) exitflag=verify("Exit now ");
  263.                              while(kbhit()) getch();
  264.                          }
  265.                          break;
  266.             }
  267.         }
  268.         if (!exitflag) exitflag=edit_parms(data); /* edit the parameters    */
  269.     } /* end of while(!exit_flag) */
  270.     closegraph();
  271.     printf("Thanks for using Lissajous Ver. %s\n",VERSION);
  272.     printf("By Aaron Caba and Dan Farmer\n");
  273.     return(0);
  274. } /* end main */
  275.  
  276.  
  277. /* Rotate the figure by 'angle_str' degrees */
  278. void rotate_fig(struct queue_type queue[], int num,
  279.                 char *angle_str, char *axis)
  280. {
  281.     int i, ret;
  282.     float  a, b,    /* work variables */
  283.           at,bt,
  284.           angle;
  285.  
  286.     disp_message(field[ROTATE].label);
  287.     parm_field=FALSE;
  288.     ret=fieldinput(ROTATE, angle_str, field[ROTATE].label, 0);
  289.     if (ret==ESC) {
  290.         if (verify(" Quit now ")) {
  291.             clean_up_graph();
  292.             exit(0);
  293.         }
  294.         else return;
  295.     }
  296.     
  297.     disp_message("Rotating...");
  298.     angle=PI/180.0*atof(angle_str);
  299.     if (angle != 0) {
  300.         for (i=0; i<num; i++) {
  301.  
  302.             switch (axis[0]) {
  303.                 case 'X' :
  304.                     a=queue[i].z;  b=queue[i].x;
  305.                     break;
  306.                 case 'Y' :
  307.                     a=queue[i].x;  b=queue[i].y;
  308.                     break;
  309.                 case 'Z' :
  310.                     a=queue[i].y;  b=queue[i].z;
  311.                     break;
  312.             }
  313.  
  314.             at=a*cos(angle) - b*sin(angle);
  315.             bt=a*sin(angle) + b*cos(angle);
  316.             a=at;   b=bt;
  317.  
  318.             switch(axis[0]) {
  319.                 case 'X' :
  320.                     queue[i].z=a;  queue[i].x=b;
  321.                     break;
  322.                 case 'Y' :
  323.                     queue[i].x=a;  queue[i].y=b;
  324.                     break;
  325.                 case 'Z' :
  326.                     queue[i].y=a;  queue[i].z=b;
  327.                     break;
  328.             }
  329.         }
  330.     }
  331. } /* end rotate_fig */
  332.  
  333.  
  334.  
  335. /* Display the sorted spheres in the viewing window, with option
  336.    to pause/abort when a key is pressed */
  337. void disp_spheres(struct queue_type queue[], int index[], 
  338.                   int numspheres, char *data[])
  339. {
  340.     int i, color,
  341.         r, ret=TRUE,
  342.         xscr, yscr;     /* screen coordinates of the sphere */
  343.     char msg[71];
  344.  
  345.     disp_message("Press any key to pause display...");
  346.     setviewport(winleft+8,wintop+8,winright-8,winbottom-8,CLIP_ON);
  347.     clearviewport();
  348.     i=0;
  349.     while (i<numspheres && ret==TRUE) {
  350.         color=colors[i % maxcolors];
  351.  
  352.         /* adjust coords for the center of the viewing window */
  353.         if (!strcmp("X",data[AXIS])) {
  354.             xscr=(int)queue[index[i]].y;
  355.             yscr=(int)queue[index[i]].z;
  356.             r=scaled_radius(atoi(data[SPH_RADIUS]),queue[index[i]].x);
  357.         }
  358.         else if (!strcmp("Y",data[AXIS])) {
  359.             xscr=(int)queue[index[i]].z;
  360.             yscr=(int)queue[index[i]].x;
  361.             r=scaled_radius(atoi(data[SPH_RADIUS]),queue[index[i]].y);
  362.         }
  363.         else if (!strcmp("Z",data[AXIS])) {
  364.             xscr=(int)queue[index[i]].x;
  365.             yscr=(int)queue[index[i]].y;
  366.             r=scaled_radius(atoi(data[SPH_RADIUS]),queue[index[i]].z);
  367.         }
  368.         xscr += winxcenter;
  369.         yscr += winycenter;
  370.  
  371.         /* to reverse the graphics system's upside-down 'up' vector */
  372.         yscr = (winbottom - wintop) - yscr;
  373.  
  374.         setcolor(color);
  375.         setfillstyle(SOLID_FILL,color);
  376.         fillellipse(xscr,yscr,r,r);
  377.         if (kbhit()) {              /* pause and/or stop displaying spheres */
  378.             while (kbhit()) getch();
  379.             disp_axes(data[AXIS]);
  380.             setviewport(0,0,cols,rows,CLIP_OFF);
  381.             sprintf(msg,"Paused at %i spheres.  Continue display ",i+1);
  382.             ret=verify(msg);
  383.             disp_message("Press any key to pause display...");
  384.             setviewport(winleft+8,wintop+8,winright-8,winbottom-8,CLIP_ON);
  385.         }
  386.         i++;
  387.     }
  388.  
  389.     /* draw coordinate axes for reference */
  390.     disp_axes(data[AXIS]);
  391.     setviewport(0,0,cols,rows,CLIP_OFF);
  392. } /* end disp_spheres */
  393.  
  394.  
  395. /* draws a set of coordinate axes on the display screen */
  396. void disp_axes(char *axis)
  397. {
  398.     int save_color=getcolor();
  399.     char a[2], b[2];
  400.  
  401.     /* assign and draw the axis labels */
  402.     switch (axis[0]) {
  403.         case 'X':
  404.             strcpy(a,"Z");
  405.             strcpy(b,"Y");
  406.             break;
  407.         case 'Y':
  408.             strcpy(a,"X");
  409.             strcpy(b,"Z");
  410.             break;
  411.         case 'Z':
  412.             strcpy(a,"Y");
  413.             strcpy(b,"X");
  414.             break;
  415.     }
  416.     disp_text(2,0,a,EGA_BLUE);
  417.     disp_text(4,2,b,EGA_BLUE);
  418.  
  419.     /* draw the axis arrows */
  420.     setcolor(EGA_BLUE);
  421.     line(0,5,5,0);
  422.     line(5,0,10,5);
  423.     line(5,0,5,20);
  424.     line(5,20,25,20);
  425.     line(25,20,20,15);
  426.     line(25,20,20,25);
  427.  
  428.     /* restore original color */
  429.     setcolor(save_color);
  430. }
  431.  
  432.  
  433.  
  434. /* This isn't as bad as it looks!  It scales the radius of the 
  435.    displayed spheres to simulate perspective.  I put the (float)'s in to
  436.    stop integer math from rounding.
  437.    Returns the scaled radius */
  438. int scaled_radius(int r, int z)
  439. {
  440.     if ((VIEWER-z) <= 0) return(0);
  441.     else return((int)ceil( (float)r * (float)VIEWER / (float)(VIEWER-z) ));
  442. }
  443.  
  444.  
  445. /* Make sure all entered data is in the proper format or range, assign
  446.    defaults if data isn't O.K. */
  447. void check_data(char *data[])
  448. {
  449.     int i, tempi;
  450.     double tempf;
  451.     char *endptr;
  452.  
  453.     for(i=0; i < MAXFIELDS; i++) {
  454.         switch(field[i].type) {
  455.             case DECIMAL:
  456.                 tempf=strtod(data[i],&endptr);
  457.                 if ((strcmp(endptr,"")) || (tempf == 0.0)) 
  458.                     strcpy(data[i],field_default[i]);
  459.                 break;
  460.             case INTEGER:
  461.                 switch(i) {
  462.                     case ALGO:
  463.                         tempi=atoi(data[ALGO]);
  464.                         if (tempi > MAXALGO) itoa(MAXALGO,data[ALGO],10);
  465.                         else if (tempi == 0) strcpy(data[i],field_default[i]);
  466.                         break;
  467.                     case SPHERES:
  468.                         tempi=atoi(data[SPHERES]);
  469.                         if (tempi > MAXSPHERES)
  470.                             itoa(MAXSPHERES,data[SPHERES],10);
  471.                         else if (tempi < 1)
  472.                             strcpy(data[i],field_default[i]);
  473.                         break;
  474.                     default:
  475.                         if (atoi(data[i]) == 0) {
  476.                             strcpy(data[i],field_default[i]);
  477.                         }
  478.                         break;
  479.                 }
  480.                 break;
  481.             case SIGNED_INTEGER:
  482.                 if (atoi(data[i])==0)
  483.                     strcpy(data[i],field_default[i]);
  484.                 break;
  485.             case XYZ:
  486.                 if (strlen(data[i]) == 0) strcpy(data[i],field_default[i]);
  487.                 else strcpy(data[i],strupr(data[i]));
  488.                 break;
  489.         } /* end switch */
  490.     } /* end for loop */
  491. } /* end check_data */
  492.  
  493.  
  494. /* Edit the generation parameters.
  495.    Return [EXIT || NO_EXIT] */
  496. int edit_parms(char *data[])
  497. {
  498.     int fieldnum=0, ret, done, exitflag;
  499.  
  500.     done=exitflag=FALSE;
  501.     parm_field=TRUE;
  502.     disp_message("Press F10 to restore defaults.");
  503.     while (!exitflag && !done) {
  504.         ret=fieldinput(fieldnum,data[fieldnum],"Press F10 to restore defaults.",0);
  505.         check_data(data);               /* make sure data is valid  */
  506.         disp_data(data);
  507.         switch(ret) {
  508.             case UP: fieldnum--;
  509.                      if (fieldnum < 0) fieldnum=0;
  510.                      break;
  511.             case PGDN: done=TRUE;
  512.                        break;
  513.             case PGUP: fieldnum=0;
  514.                        break;
  515.             case ESC:  if (verify(" Quit now ")) exitflag=TRUE;
  516.                        else disp_message("Press F10 to restore defaults.");
  517.                        break;
  518.             case F10:  fieldnum=0;
  519.                        assign_default(data);
  520.                        disp_data(data);
  521.                        break;
  522.             case DOWN:
  523.             default:   fieldnum++;
  524.                        if (fieldnum < PARMFIELDS) break;
  525.                        else { done=TRUE; break;}
  526.         }
  527.     }
  528.     if (exitflag) return(EXIT);
  529.     return(NO_EXIT);
  530. } /* end edit_parms */
  531.  
  532.  
  533. /*  Print current values in all data fields */
  534. void disp_data(char *data[])
  535. {
  536.     #define EQN_COLOR    EGA_BLUE
  537.     int i;
  538.     char x_eqn1[21], x_eqn2[21], y_eqn1[21], y_eqn2[21], z_eqn[21];
  539.  
  540.     parm_field=TRUE;
  541.     for(i=0; i < PARMFIELDS; i++) disp_field(i,data[i],EGA_DARKGRAY,0);
  542.  
  543.     /* print out formulas coresponding to algo # */
  544.     switch(atoi(data[ALGO])) {
  545.         case 1:
  546.             strcpy(x_eqn1,"x=R*(sin(A*t)*");
  547.             strcpy(x_eqn2,"  cos(B*t)^X)");
  548.             strcpy(y_eqn1,"y=R*(sin(A*t)*");
  549.             strcpy(y_eqn2,"  sin(B*t)^Y)");
  550.             strcpy(z_eqn,"z=R*(cos(A*t)^Z)");
  551.             break;
  552.         case 2:
  553.             strcpy(x_eqn1,"x=R*(sin(A*t)*");
  554.             strcpy(x_eqn2,"  cos(B*t)^X)");
  555.             strcpy(y_eqn1,"y=R*(cos(A*t)*");
  556.             strcpy(y_eqn2,"  cos(B*t)^Y)");
  557.             strcpy(z_eqn,"z=R*(sin(A*t)^Z)");
  558.             break;
  559.         case 3:
  560.             strcpy(x_eqn1,"x=R*(sin(A*t)*");
  561.             strcpy(x_eqn2,"  sin(B*t)^X)");
  562.             strcpy(y_eqn1,"y=R*(sin(A*t)*");
  563.             strcpy(y_eqn2,"  cos(B*t)^Y)");
  564.             strcpy(z_eqn,"z=R*(sin(A*t)^Z)");
  565.             break;
  566.         case 4:
  567.             strcpy(x_eqn1,"x=R/4*(A*sin(2*");
  568.             strcpy(x_eqn2,"  (t-PI/13))^X)");
  569.             strcpy(y_eqn1,"y=R/4*(-B*");
  570.             strcpy(y_eqn2,"  cos(t)^Y)");
  571.             strcpy(z_eqn,"z=R*(sin(A*t)^Z)");
  572.             break;
  573.         case 5: 
  574.             strcpy(x_eqn1,"x=R*(sin(A*t)*");
  575.             strcpy(x_eqn2,"  (cos(A*t)^X))");
  576.             strcpy(y_eqn1,"y=R*(sin(B*t)*");
  577.             strcpy(y_eqn2,"  (sin(B*t)^Y))");
  578.             strcpy(z_eqn,"z=R*(sin(t)^Z)");
  579.             break;
  580.     }
  581.     erase_text(field[ALGO_EQN].x,field[ALGO_EQN].y+1,20);
  582.     disp_text(field[ALGO_EQN].x, field[ALGO_EQN].y+1, x_eqn1, EQN_COLOR);
  583.     erase_text(field[ALGO_EQN].x,field[ALGO_EQN].y+2,20);
  584.     disp_text(field[ALGO_EQN].x, field[ALGO_EQN].y+2, x_eqn2, EQN_COLOR);
  585.  
  586.     erase_text(field[ALGO_EQN].x,field[ALGO_EQN].y+3,20);
  587.     disp_text(field[ALGO_EQN].x, field[ALGO_EQN].y+3, y_eqn1, EQN_COLOR);
  588.     erase_text(field[ALGO_EQN].x,field[ALGO_EQN].y+4,20);
  589.     disp_text(field[ALGO_EQN].x, field[ALGO_EQN].y+4, y_eqn2, EQN_COLOR);
  590.  
  591.     erase_text(field[ALGO_EQN].x,field[ALGO_EQN].y+5,20);
  592.     disp_text(field[ALGO_EQN].x, field[ALGO_EQN].y+5, z_eqn, EQN_COLOR);
  593.  
  594.     #undef EQN_COLOR
  595. }
  596.  
  597.  
  598.  
  599. /* Draw a gui-like panel from (wleft,wtop)-(wright,wbottom) */
  600. void guipanel(int wleft, int wtop, int wright, int wbottom, int toggle)
  601. {
  602. /* Parameter TOGGLE := -1 FOR INSET, 1 FOR OUTSET                       */
  603. /*                     -2 FOR INSET 2 DEEP, 3 TO OUTSET 3 DEEP, ETC.    */
  604.     int depth,i,inset;
  605.  
  606.     depth=abs(toggle);
  607.     inset=(toggle <0);
  608.  
  609.     for(i=0; i<=depth; i++) {
  610.         if (inset) {                        /* INSET PANEL  */
  611.             setcolor(8);
  612.             line(wleft+i,  wtop+i,wleft+i,wbottom-i);       /* left side    */
  613.             line(wleft+i,  wtop+i ,wright-i,wtop+i);        /* top line     */
  614.             setcolor(15);
  615.             line(wleft+i,  wbottom-i,wright-i,wbottom-i);   /* bottom line  */
  616.             line(wright-i, wtop+i,wright-i,wbottom-i);      /* right side   */
  617.         }
  618.         else {                              /* OUTSET PANEL */
  619.             setcolor(15);
  620.             line(wleft+i,  wtop+i,wleft+i,wbottom-i);       /* left side    */
  621.             line(wleft+i,  wtop+i,wright-i,wtop+i);         /* top line     */
  622.             setcolor(8);
  623.             line(wleft+i,  wbottom-i,wright-i,wbottom-i);   /* bottom line  */
  624.             line(wright-i, wtop+i,wright-i,wbottom-i);      /* right side   */
  625.         }
  626.     }
  627. } /* end guipanel */
  628.  
  629.  
  630. void guibolt(int x, int y, int r, int toggle)
  631. {
  632. /* Parameter TOGGLE := -1 FOR iNSET, 1 FOR OUTSET                       */
  633. /*                     -2 FOR iNSET 2 DEEP, 3 TO OUTSET 3 DEEP, ETC.    */
  634.     int depth, i, inset;
  635.  
  636.     depth=abs(toggle);
  637.     inset=(toggle<0);
  638.  
  639.     for(i=0; i<=depth; i++) {
  640.         if (inset) {
  641.             setcolor(15);
  642.             arc(x, y, 0.5*PI,1.5*PI, r);
  643.             arc(x, y, 0.5*PI,1.5*PI, r);
  644.         }
  645.         else {
  646.             setcolor(8);
  647.             arc(x, y, 0.5*PI,1.5*PI, r);
  648.             arc(x, y, 0.5*PI,1.5*PI, r);
  649.         }
  650.     }
  651. }
  652.  
  653.  
  654. /* Draw the gui-pannels, credits, and display the field labels */
  655. void disp_bkground(void)
  656. {
  657.     int color,i,y=22,
  658.         bolt_dy=0, win_dy=0;
  659.  
  660.     if(getgraphmode() == VGAHI) {
  661.         y += 12;
  662.         bolt_dy=120;
  663.         win_dy=115;
  664.     }
  665.  
  666.     /* Create a GUI-looking window for the data entry fields. */
  667.     guipanel(8,wintop,winleft-7,winbottom,2);
  668.  
  669.     /* print the field labels */
  670.     for(i=0; i<PARMFIELDS; i++)
  671.         disp_text(field[i].x, field[i].y, field[i].label, EGA_YELLOW);
  672.     disp_text(field[ALGO_EQN].x,field[ALGO_EQN].y,"Equations:", EGA_MAGENTA);
  673.  
  674.     /* Panel for credits and logo                           */
  675.     guipanel(16,215+win_dy,winleft-15,winbottom-6,1);
  676.     color=EGA_WHITE;
  677.     /* The raised panel can be printed in from rows 34-40   */
  678.     /* starting at column 3 for a length of 17 Characters.  */
  679.     disp_text(3,y  ,"  3-D Lissajous  ",color);
  680.     disp_text(3,y+1,"    Generator    ",color);
  681.     disp_text(3,y+5,"  By Aaron Caba  ",color);
  682.     disp_text(3,y+6," and Dan Farmer  ",color);
  683.  
  684.     /* Colored Dots "Logo" */
  685. /*    guibolt( 65,BOLT_HT+bolt_dy,10,1);
  686.     guibolt( 90,BOLT_HT+bolt_dy,10,1);
  687.     guibolt(115,BOLT_HT+bolt_dy,10,1);
  688. */
  689.     color=EGA_GREEN;
  690.     setcolor(color);    circle( 65,BOLT_HT+bolt_dy,8);
  691.     setfillstyle(SOLID_FILL,color); floodfill(65,BOLT_HT+bolt_dy,color);
  692.  
  693.     color=EGA_MAGENTA;
  694.     setcolor(color);    circle( 90,BOLT_HT+bolt_dy,8);
  695.     setfillstyle(SOLID_FILL,color); floodfill(90,BOLT_HT+bolt_dy,color);
  696.  
  697.     color=EGA_BLUE;
  698.     setcolor(color);    circle(115,BOLT_HT+bolt_dy,8);
  699.     setfillstyle(SOLID_FILL,color); floodfill(115,BOLT_HT+bolt_dy,color);
  700.  
  701. /*    guibolt(10,8,4,1);              /* UPPER LEFT BOLT  */
  702.     guibolt(cols-10,8,4,1);         /* UPPER RIGHT BOLT */
  703. */
  704.     /* Create panel for messages at screen bottom */
  705.     guipanel(8,winbottom+8,winright,rows-8,2);
  706. /*    guibolt(24,rows-24,4,1);
  707.     guibolt(winright-24,rows-24,4,1);
  708. */
  709.     /* Create a GUI-looking window for the image display */
  710.     guipanel(winleft,wintop,winright,winbottom,-3);   /* SUNKEN PANEL */
  711. } /* end disp_background */
  712.  
  713.  
  714. /* These calculate the (x,y,z) coordinate at time 't' */
  715. void algo1(int t, int r, float a, float b,
  716.            int exponent_x, int exponent_y, int exponent_z,
  717.            float *x, float *y, float *z)
  718. {   
  719.     *x = r*(sin(a*t)* pow(cos(b*t),exponent_x));
  720.     *y = r*(sin(a*t)* pow(sin(b*t),exponent_y));
  721.     *z = r*pow(cos(a*t),exponent_z);
  722. }
  723.  
  724. void algo2(int t, int r, float a, float b,
  725.            int exponent_x, int exponent_y, int exponent_z,
  726.            float *x, float *y, float *z)
  727. {
  728.     *x = r*(sin(a*t)*pow(cos(b*t),exponent_x));
  729.     *y = r*(cos(a*t)*pow(cos(b*t),exponent_y));
  730.     *z = r*pow(sin(a*t),exponent_z);
  731. }
  732.  
  733. void algo3(int t, int r, float a, float b,
  734.            int exponent_x, int exponent_y, int exponent_z,
  735.            float *x, float *y, float *z)
  736. {
  737.     *x = r*(sin(a*t)*pow(sin(b*t),exponent_x));
  738.     *y = r*(sin(a*t)*pow(cos(b*t),exponent_y));
  739.     *z = r*pow(sin(a*t),exponent_z);
  740. }
  741.  
  742. void algo4(int t, int r, float a, float b,
  743.            int exponent_x, int exponent_y, int exponent_z,
  744.            float *x, float *y, float *z)
  745. {
  746.     *x = r/4 * pow(a*sin(2*(t-PI/13)),exponent_x);
  747.     *y = r/4 * pow(-b*cos(t),exponent_y);
  748.     *z = r   * pow(sin(a*t),exponent_z);
  749. }
  750.  
  751. void algo5(int t, int r, float a, float b,
  752.            int exponent_x, int exponent_y, int exponent_z,
  753.            float *x, float *y, float *z)
  754. {
  755.     *x = r*(sin(a*t)*pow(cos(a*t),exponent_x));
  756.     *y = r*(sin(b*t)*pow(sin(b*t),exponent_y));
  757.     *z = r*pow(sin(t),exponent_z);
  758. }
  759.  
  760.  
  761. /* --- Sort the circles on 'axis', from most distant to closest for simple
  762.        "hidden line removal".  Farthest will be drawn first and overlapped
  763.        by the nearer circles.
  764.        Parms: queue = array of values needed sorting.
  765.               index = single dimension array of integers indexing queue().
  766.               left  = lowest index #.
  767.               right = highest index #.
  768.               axis  = string of either "X", "Y", or "Z"
  769. */
  770. void quicksort(struct queue_type queue[], int *index, 
  771.                int left, int right, char *axis)
  772. {
  773.     int i,j,
  774.         *lstack, *rstack;
  775.  
  776.     if ((right-left) >= 1) {
  777.         if (((lstack=malloc( 1+sizeof(int)*right )) == NULL) ||
  778.             ((rstack=malloc( 1+sizeof(int)*right )) == NULL))
  779.                 error_fn(EMEM,"quicksort");
  780.  
  781.         median_index=index[(right+left)/2];
  782.         median=component(&queue[median_index],axis);
  783.         i=left-1; j=right+1;
  784.  
  785.         for(k=left; k <= right; k++) {
  786.             if (component(&queue[index[k]],axis) < median) {  
  787.                 i++;
  788.                 lstack[i]=index[k];
  789.             } else if (component(&queue[index[k]],axis) > median) {  
  790.                 j--;
  791.                 rstack[j]=index[k];
  792.             }
  793.         }
  794.         for(k=left; k <= i; k++) {
  795.             index[k]=lstack[k];
  796.         }
  797.         index[k]=median_index;
  798.         for(k=j; k <= right; k++) {
  799.             index[k]=rstack[k];
  800.         }
  801.         free(lstack);
  802.         free(rstack);
  803.         quicksort(queue, index, left, i, axis);
  804.         quicksort(queue, index, j, right, axis);
  805.     }
  806. }
  807.  
  808.  
  809. void clean_up_graph(void)
  810. {
  811.     closegraph();
  812. }
  813.